#include "SIPMessage.h"
#include "sip_error.h"
#include "uax_net.h"
#include "sip_uac.h"
#include "log4z.h"

CSIPMessage::CSIPMessage()
{
    mGB35114 = 0;
    mfdClient = -1;
    thread_handle = NULL;
    hSIPInit = UAXCreateHandle(HandleCallback, this);
}

CSIPMessage::~CSIPMessage()
{
    if (NULL != hSIPInit) {
        UAXCloseHandle(hSIPInit);
        hSIPInit = NULL;
    }
}

int CSIPMessage::HandleCallback(void* sip, UAEncrypt* crypt, int flags, const char* body, int size, void* user)
{
    int status_code = 0;
    CSIPMessage* pthis = (CSIPMessage*)user;
   
    if (flags == SIP_MSG_TASK_QUEUE) {
        if (pthis->mGB35114) {
            if (UAXGetMessageMethod(sip) == SIP_MT_REGISTER) {
                return  pthis->SendSipMessage(sip, crypt, CRT_AUTHORIZATION_INIT);
            }
            else if (UAXGetMessageMethod(sip) == SIP_MT_MESSAGE) {
               return pthis->SendSipMessage(sip, crypt, CRT_AUTHORIZATION_NOTE);
            }
        }
        return pthis->SendSipMessage(sip,CRT_AUTHORIZATION_NULL);
    }

    if (flags == SIP_MSG_SUCCESS) {
         if (UAXMessageIsResponse(sip,&status_code)) {
            pthis->OnResponseMessage(sip, crypt, body, size, status_code);
         }else {
             pthis->OnRequestMessage(sip, crypt, body, size);
         }
    }

    return 0;
}

int  CSIPMessage::SendUDPData(sockaddr_in* addr, const char* data, int len)
{
    socklen_t fname = sizeof(struct sockaddr_in);
    return sendto(mfdClient,data,len,0,(sockaddr*)addr, fname);
}

int  CSIPMessage::SendTCPData(const char* data, int len)
{
    return send(mfdClient, data, len, 0);
}

int CSIPMessage::SendSipMessage(void* sip, int enc_type)
{
    return SendSipMessage(sip,&mUAEncrypt, enc_type);
}

int CSIPMessage::SendSipMessage(void* sip, UAEncrypt* crypt, int enc_type)
{
    int size;
    char* buffer = 0;
    if (UAXEncAuthenticate(sip, &mUAContext, crypt, enc_type)) {
        return -1;
    }

    if (UAXTranslateMessage(hSIPInit, sip, &buffer, &size)) {
        return -1;
    }
    LOGFMTD("\n%s", buffer);
    if (mUAContext.protocol == SIP_UDP) {
        sockaddr_in addr = { 0 };
        ipv4_address(&addr,
            mUAContext.uas_ip,
            mUAContext.uas_port);
        return SendUDPData(&addr, buffer, size);
    }

    return SendTCPData(buffer, size);
}

int CSIPMessage::OpenChannel(UAContext* UContext, int iGB35114)
{
    if (NULL != UContext) {
        if (SIP_UDP == UContext->protocol) {
            if (udp_bind(&mfdClient, UContext->uac_ip, UContext->uac_port)) {
                fdClose(mfdClient);
                return -1;
            }
        }else {
            if (tcp_bind(&mfdClient, UContext->uac_ip, UContext->uac_port)) {
                fdClose(mfdClient);
                return -1;
            }

            if (tcp_connect(mfdClient, UContext->uas_ip, UContext->uas_port, 5)) {
                fdClose(mfdClient);
                return -1;
            }
        }
        mGB35114 = iGB35114;
        memcpy(&mUAContext, UContext, sizeof(UAContext));

        if (NULL != hSIPInit) {
            UAXCreateQueueTask(hSIPInit, &mUAContext,
                mUAContext.uac_code, SIP_MT_REGISTER, 3600, 0, 0, 0);

        }

        return xx_create_thread(&thread_handle,ThreadProc,this,NULL);
    }
      
    return ERR_BAD_PARAMETER;
 }

int CSIPMessage::OnAckReq(void* sip,  UAEncrypt* crypt, const char* body, int size)
{
    return SIP_MSG_SUCCESS;
}

int CSIPMessage::OnByeReq(void* sip,  UAEncrypt* crypt, const char* body, int size)
{
    return SIP_MSG_SUCCESS;
}

int CSIPMessage::OnByeRsp(void* sip,  UAEncrypt* crypt, const char* body, int size, int status_code)
{
    return SIP_MSG_SUCCESS;
}

int CSIPMessage::OnInfoReq(void* sip,  UAEncrypt* crypt, const char* body, int size)
{
    return SIP_MSG_SUCCESS;
}

int CSIPMessage::OnInfoRsp(void* sip,  UAEncrypt* crypt, const char* body, int size, int status_code)
{
    return SIP_MSG_SUCCESS;
}

int CSIPMessage::OnRegistReq(void* sip,  UAEncrypt* crypt, const char* body, int size)
{
    return SIP_MSG_SUCCESS;
}

int CSIPMessage::OnRegistRsp(void* sip,  UAEncrypt* crypt, const char* body, int size, int status_code)
{
    if (200 == status_code) {
        UAXCreateQueueTask(hSIPInit, &mUAContext,
                mUAContext.uac_code, SIP_MT_HEARTBEAT, 20, 0, 0, 0);
    }
    else if (401 == status_code) {
        void * req = UACRegisterReq(&mUAContext, 3600);

        SendSipMessage(req, crypt, CRT_AUTHORIZATION_MD5);
    }
    return SIP_MSG_SUCCESS;
}

int CSIPMessage::OnCancelReq(void* sip,  UAEncrypt* crypt, const char* body, int size)
{
    return SIP_MSG_SUCCESS;
}

int CSIPMessage::OnCancelRsp(void* sip,  UAEncrypt* crypt, const char* body, int size, int status_code)
{
    return SIP_MSG_SUCCESS;
}

int CSIPMessage::OnInviteReq(void* sip,  UAEncrypt* crypt, const char* body, int size)
{
    return SIP_MSG_SUCCESS;
}

int CSIPMessage::OnInviteRsp(void* sip,  UAEncrypt* crypt, const char* body, int size, int status_code)
{
    return SIP_MSG_SUCCESS;
}

int CSIPMessage::OnNotifyReq(void* sip,  UAEncrypt* crypt, const char* body, int size)
{
    return SIP_MSG_SUCCESS;
}

int CSIPMessage::OnNotifyRsp(void* sip,  UAEncrypt* crypt, const char* body, int size, int status_code)
{
    return SIP_MSG_SUCCESS;
}

int CSIPMessage::OnMessageReq(void* sip,  UAEncrypt* crypt, const char* body, int size)
{
    void* req = UACMessageRsp(sip, &mUAContext, 200);
    SendSipMessage(req, crypt, CRT_AUTHORIZATION_NULL);

    return SIP_MSG_SUCCESS;
}

int CSIPMessage::OnMessageRsp(void* sip,  UAEncrypt* crypt, const char* body, int size, int status_code)
{


    return SIP_MSG_SUCCESS;
}

int CSIPMessage::OnSubcribeReq(void* sip,  UAEncrypt* crypt, const char* body, int size)
{
    return SIP_MSG_SUCCESS;
}

int CSIPMessage::OnSubcribeRsp(void* sip,  UAEncrypt* crypt, const char* body, int size, int status_code)
{
    return SIP_MSG_SUCCESS;
}

int CSIPMessage::OnRequestMessage(void* sip,  UAEncrypt* crypt, const char* body, int size)
{
    int sip_type = UAXGetMessageMethod(sip);
    if      (sip_type == SIP_MT_MESSAGE)    { OnMessageReq(sip, crypt, body,size); }
    else if (sip_type == SIP_MT_INVITE)     { OnInviteReq(sip, crypt, body, size); }
    else if (sip_type == SIP_MT_BYE)        { OnByeReq(sip, crypt, body, size); }
    else if (sip_type == SIP_MT_ACK)        { OnAckReq(sip, crypt, body, size); }
    else if (sip_type == SIP_MT_NOTIFY)     { OnNotifyReq(sip, crypt, body, size); }
    else if (sip_type == SIP_MT_REGISTER)   { OnRegistReq(sip, crypt, body, size); }
    else if (sip_type == SIP_MT_SUBSCRIBE)  { OnSubcribeReq(sip, crypt, body, size); }
    else if (sip_type == SIP_MT_INFO)       { OnInfoReq(sip, crypt, body, size); }
    else if (sip_type == SIP_MT_CANCLE)     { OnCancelReq(sip, crypt, body, size); }
    return SIP_MSG_SUCCESS;
 }

int CSIPMessage::OnResponseMessage(void* sip,  UAEncrypt* crypt, const char* body, int size, int status_code)
{
    int sip_type = UAXGetMessageMethod(sip);
    if      (sip_type == SIP_MT_MESSAGE)    { OnMessageRsp(sip, crypt, body, size, status_code); }
    else if (sip_type == SIP_MT_INVITE)     { OnInviteRsp(sip, crypt, body, size, status_code); }
    else if (sip_type == SIP_MT_BYE)        { OnByeRsp(sip, crypt, body, size, status_code);  }
    else if (sip_type == SIP_MT_NOTIFY)     { OnNotifyRsp(sip, crypt, body, size, status_code); }
    else if (sip_type == SIP_MT_REGISTER)   { OnRegistRsp(sip, crypt, body, size, status_code); }
    else if (sip_type == SIP_MT_SUBSCRIBE)  { OnSubcribeRsp(sip, crypt, body, size, status_code);  }
    else if (sip_type == SIP_MT_INFO)       { OnInfoRsp(sip, crypt, body, size, status_code);   }
    else if (sip_type == SIP_MT_CANCLE)     { OnCancelRsp(sip, crypt, body, size, status_code); }
    return SIP_MSG_SUCCESS;
 }

void CSIPMessage::ThreadProc(void* arg)
{
    struct timeval tv;
    fd_set fdRead = { 0 };
    struct sockaddr_in fdaddr;
    CSIPMessage* pthis = (CSIPMessage*)arg;
    char* buffer = (char*)malloc(0x2000 + 16);
    socklen_t fname = sizeof(struct sockaddr_in);
    if (NULL == buffer) {
        return;
    }

    pthis-> thread_exit = 0;
    while (0 == pthis->thread_exit)
    {
        tv.tv_sec = 0;
        FD_ZERO(&fdRead);
        tv.tv_usec = 200 * 1000;
        FD_SET(pthis->mfdClient, &fdRead);
#ifdef WIN32
        if (select(pthis->mfdClient, &fdRead, NULL, NULL, &tv) > 0) {
#else
        if (select(m_fdClient + 1, &fdRead, NULL, NULL, &tv) > 0) {
#endif
            if (pthis->mUAContext.protocol == SIP_UDP) {
                int dwByte = recvfrom(pthis->mfdClient, buffer, 0x2000,
                    0, (struct sockaddr*)&fdaddr, &fname);
                if (dwByte > 0) {
                    buffer[dwByte] = 0;
                    LOGFMTD("\n%s", buffer);
                    UAXParseUdpMessage(pthis->hSIPInit,buffer,dwByte);
                }
            }
            else {
                int dwByte = recv(pthis->mfdClient, buffer ,0x2000, 0);
                if (dwByte > 0) {
                    UAXParseUdpMessage(pthis->hSIPInit, buffer, dwByte);
                }
                else if (dwByte == 0) {
                    break;
                }
            }
        }
    }

    if (NULL != buffer) {
        free(buffer);
        buffer = NULL;
    }
}

int UAXEncAuthenticate(void* sip, UAContext* UContext, UAEncrypt* crypt, int enc_type)
{
    if (enc_type == CRT_AUTHORIZATION_INIT) {

        time_t tt;
        struct tm* atm;
        char tms[64] = { 0 };
        time(&tt);
        atm = localtime(&tt);
        strftime(tms, 32, "%Y-%m-%dT%H:%M:%S", atm);

        crypt->crypt_type = CRT_AUTHORIZATION_INIT;
        snprintf(crypt->keyversion, 63, "\"%s\"", tms);
        strcpy(crypt->algorithm, "\"A:SM2;H:SM3;S:SM1/OFB/PKCS5,SM1/CBC/PKCS5,SM4/OFB/PKCS5,SM4/CBC/PKCS5;SI:SM3-SM2\"");
        strcpy(crypt->capability, "Capability");
        sip_enc_authorization(sip, crypt);
    }
    else if (enc_type == CRT_AUTHORIZATION_DIGEST) {
        crypt->crypt_type = CRT_AUTHORIZATION_DIGEST;
        snprintf(crypt->qop, 63, "auth");
        snprintf(crypt->capability, 63, "Digest");
        snprintf(crypt->realm, 63, "%s", UContext->uac_domain);
        snprintf(crypt->nonce, 127, "%s%s",UContext->uac_code,UContext->uas_domain);
        sip_enc_authorization(sip, crypt);
    }
    else if (enc_type == CRT_AUTHORIZATION_NOTE) {
        int nRet = -1;
        
        return nRet;
    }
    else if (enc_type == CRT_AUTHORIZATION_SIGN1) {
        if (0 == strcasecmp(crypt->capability, "Bidirection")) {
            
        }
    }
    else if (enc_type == CRT_AUTHORIZATION_SIGN2) {
      
    }
    else if (enc_type == CRT_AUTHORIZATION_MD5) {
           sip_md5_authorization(sip, UContext-> uac_code, UContext->password, UContext->uas_domain, crypt->realm, crypt->nonce, crypt->qop);
    }
    return 0;
}